home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / mxcode / adlib / adlib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-09  |  9.9 KB  |  377 lines

  1. /* C Header File: ADLIB *****************************************************
  2.  
  3. Author:        Kevin A. Lee
  4.  
  5. Last Amended:    27th April, 1993
  6.  
  7. Description:    Low-level interface to the Adlib (or compatible)
  8.         FM sound card. All information gleaned from
  9.         Jeffrey S. Lee's "Programming the Adlib/Sound
  10.         Blaster FM Music Chips". See Lee's document for
  11.         further information.
  12.  
  13. Compiled succesfully under Turbo C, Borland C++,
  14. and Microsoft Quick C (all latest versions).
  15.  
  16. ****************************************************************************/
  17.  
  18. #define MIN_REGISTER        0x01
  19. #define MAX_REGISTER        0xF5
  20. #define ADLIB_FM_ADDRESS    0x388       /* adlib address/status register */
  21. #define ADLIB_FM_DATA       0x389       /* adlib data register           */
  22.  
  23. #ifndef BYTE
  24. #define BYTE unsigned char
  25. #endif
  26.  
  27.  
  28. /*
  29. * FM Instrument definition for .SBI files - SoundBlaster instrument
  30. * - these are the important parts - we will skip the header, but since
  31. *   I am not sure where it starts and ends so I have had to guess.
  32. *   However it SEEMS! to work. Each array has two values, one for
  33. *   each operator.
  34. */
  35. typedef struct
  36. {
  37. BYTE SoundCharacteristic[2];    /* modulator frequency multiple...  */
  38. BYTE Level[2];                  /* modulator frequency level...     */
  39. BYTE AttackDecay[2];            /* modulator attack/decay...        */
  40. BYTE SustainRelease[2];         /* modulator sustain/release...     */
  41. BYTE WaveSelect[2];             /* output waveform distortion       */
  42. BYTE Feedback;                  /* feedback algorithm and strength  */
  43. } FMInstrument;
  44.  
  45.  
  46. /*
  47. * Enumerated F-Numbers (in octave 4) for the chromatic scale.
  48. */
  49. enum SCALE
  50. {
  51. D4b = 0x16B,    D4  = 0x181,    E4b = 0x198,    E4  = 0x1B0,
  52. F4  = 0x1CA,    G4b = 0x1E5,    G4  = 0x202,    A4b = 0x220,
  53. A4  = 0x241,    B4b = 0x263,    B4  = 0x287,    C4  = 0x2AE
  54. };
  55.  
  56.  
  57. /* function prototyping */
  58. void WriteFM(int reg, int value);
  59. int  ReadFM(void);
  60. int  AdlibExists(void);
  61. void FMReset(void);
  62. void FMKeyOff(int voice);
  63. void FMKeyOn(int voice, int freq, int octave);
  64. void FMVoiceVolume(int voice, int vol);
  65. void FMSetVoice(int voiceNum, FMInstrument *ins);
  66. int  LoadSBI(char filename[], FMInstrument *ins);
  67.  
  68. ----CUT HERE-----------------------------------------------------------------
  69. /* C Source File: ADLIB *****************************************************
  70.  
  71. Author:             Kevin A. Lee
  72.  
  73. Last Amended:       27th March, 1993
  74.  
  75. Description:        Low-level interface to the Adlib (or compatible)
  76. FM sound card. All information gleaned from
  77. Jeffrey S. Lee's "Programming the Adlib/Sound
  78. Blaster FM Music Chips". See Lee's document for
  79. further information.
  80. Compiled succesfully under Turbo C, Borland C++,
  81. and Microsoft Quick C (all latest versions).
  82.  
  83. ****************************************************************************/
  84.  
  85. #include <stdio.h>
  86. #include <conio.h>
  87. #include <time.h>
  88. #include <dos.h>
  89. #include "adlib.h"
  90.  
  91. /* comment out this line if you don't want to test the routines */
  92. #define TEST
  93.  
  94. /* local function */
  95. void Wait(clock_t wait);
  96.  
  97.  
  98.  
  99. /* Function: WriteFM ********************************************************
  100. *
  101. *      Parameters:         reg - which FM register to write to.
  102. *                          value - value to write.
  103. *
  104. *      Description:        writes a value to the specified register and
  105. *                          waits for the "official" recommended periods.
  106. *
  107. */
  108. void WriteFM(int reg, int value)
  109. {
  110. int i;
  111.  
  112. outp(ADLIB_FM_ADDRESS, (BYTE)reg);              /* set up the register  */
  113. for (i = 0; i < 6; i++) inp(ADLIB_FM_ADDRESS);  /* wait 12 cycles       */
  114. outp(ADLIB_FM_DATA, (BYTE)value);               /* write out the value  */
  115. for (i = 0; i < 35; i++) inp(ADLIB_FM_ADDRESS); /* wait 84 cycles       */
  116. } /* End of WriteFM */
  117.  
  118.  
  119.  
  120. /* Function: ReadFM *********************************************************
  121. *
  122. *      Returns:            the value in the status register.
  123. *
  124. *      Description:        return a value in the status register.
  125. *
  126. */
  127. int ReadFM(void)
  128. {
  129. return (inp(ADLIB_FM_ADDRESS));
  130. } /* End of ReadFM */
  131.  
  132.  
  133.  
  134. /* Function: AdlibExists ****************************************************
  135. *
  136. *      Returns:            1 (true) if an Adlib compatible sound card
  137. *                          is present, else 0 (false).
  138. *
  139. *      Description:        determines whether an Adlib (or compatible)
  140. *                          sound card is present.
  141. *
  142. */
  143. int AdlibExists(void)
  144. {
  145. int stat1, stat2;
  146.  
  147. WriteFM(0x04, 0x60);            /* reset both timers        */
  148. WriteFM(0x04, 0x80);            /* enable timer interrupts  */
  149. stat1 = ReadFM();               /* read status register     */
  150. WriteFM(0x02, 0xFF);
  151. WriteFM(0x04, 0x21);            /* start timer 1            */
  152. Wait(80);                       /* could do something useful*/
  153. stat2 = ReadFM();               /* read status register     */
  154. WriteFM(0x04, 0x60);            /* reset both timers        */
  155. WriteFM(0x04, 0x80);            /* enable timer interrupts  */
  156.  
  157. if (((stat1 & 0xE0) == 0x00) && ((stat2 & 0xE0) == 0xC0)) return (1);
  158. return (0);
  159. } /* End of AdlibExists */
  160.  
  161.  
  162.  
  163. /* Function: FMResest *******************************************************
  164. *
  165. *      Description:        quick and dirty sound card reset (zeros all
  166. *                          registers).
  167. *
  168. */
  169. void FMReset(void)
  170. {
  171. int i;
  172.  
  173. /* zero all registers */
  174. for (i = MIN_REGISTER; i < MAX_REGISTER+1; i++) WriteFM(i, 0);
  175.  
  176. /* allow FM chips to control the waveform of each operator */
  177. WriteFM(0x01, 0x20);
  178.  
  179. /* set rhythm enabled (6 melodic voices, 5 percussive) */
  180. WriteFM(0xBD, 0x20);
  181. } /* End of FMReset */
  182.  
  183.  
  184.  
  185. /* Function: FMKeyOff *******************************************************
  186. *
  187. *      Parameters:         voice - which voice to turn off.
  188. *
  189. *      Description:        turns off the specified voice.
  190. *
  191. */
  192. void FMKeyOff(int voice)
  193. {
  194. int regNum;
  195.  
  196. /* turn voice off */
  197. regNum = 0xB0 + voice % 11;
  198. WriteFM(regNum, 0);
  199. } /* End of FMKeyOff */
  200.  
  201.  
  202.  
  203. /* Function: FMKeyOff *******************************************************
  204. *
  205. *      Parameters:         voice - which voice to turn on.
  206. *                          freq - its frequency (note).
  207. *                          octave - its octave.
  208. *
  209. *      Description:        turns on a voice of specfied frequency and
  210. *                          octave.
  211. *
  212. */
  213. void FMKeyOn(int voice, int freq, int octave)
  214. {
  215. int regNum, tmp;
  216.  
  217. regNum = 0xA0 + voice % 11;
  218. WriteFM(regNum, freq & 0xff);
  219. regNum = 0xB0 + voice % 11;
  220. tmp = (freq >> 8) | (octave << 2) | 0x20;
  221. WriteFM(regNum, tmp);
  222. } /* End of FMKeyOn */
  223.  
  224.  
  225. /* Function: FMVoiceVolume **************************************************
  226. *
  227. *      Parameters:         voice - which voice to set volume of
  228. *                          vol - new volume value (experiment).
  229. *
  230. *      Description:        sets the volume of a voice to the specified
  231. *                          value in the range (0-63)?
  232. *
  233. */
  234. void FMVoiceVolume(int voice, int vol)
  235. {
  236. int regNum;
  237.  
  238. regNum = 0x40 + voice % 11;
  239. WriteFM(regNum, vol);
  240. } /* End of FMVoiceVolume */
  241.  
  242.  
  243.  
  244. /* Function: FMSetVoice *****************************************************
  245. *
  246. *      Parameters:         voiceNum - which voice to set.
  247. *                          ins - instrument to set voice.
  248. *
  249. *      Description:        sets the instrument of a voice.
  250. *
  251. */
  252. void FMSetVoice(int voiceNum, FMInstrument *ins)
  253. {
  254. int opCellNum, cellOffset, i;
  255.  
  256. voiceNum %= 11;
  257. cellOffset = voiceNum % 3 + ((voiceNum / 3) << 3);
  258.  
  259. /* set sound characteristic */
  260. opCellNum = 0x20 + (char)cellOffset;
  261. WriteFM(opCellNum, ins->SoundCharacteristic[0]);
  262. opCellNum += 3;
  263. WriteFM(opCellNum, ins->SoundCharacteristic[1]);
  264.  
  265. /* set level/output */
  266. opCellNum = 0x40 + (char)cellOffset;
  267. WriteFM(opCellNum, ins->Level[0]);
  268. opCellNum += 3;
  269. WriteFM(opCellNum, ins->Level[1]);
  270.  
  271. /* set Attack/Decay */
  272. opCellNum = 0x60 + (char)cellOffset;
  273. WriteFM(opCellNum, ins->AttackDecay[0]);
  274. opCellNum += 3;
  275. WriteFM(opCellNum, ins->AttackDecay[1]);
  276.  
  277. /* set Sustain/Release */
  278. opCellNum = 0x80 + (char)cellOffset;
  279. WriteFM(opCellNum, ins->SustainRelease[0]);
  280. opCellNum += 3;
  281. WriteFM(opCellNum, ins->SustainRelease[1]);
  282.  
  283. /* set Wave Select */
  284. opCellNum = 0xE0 + (char)cellOffset;
  285. WriteFM(opCellNum, ins->WaveSelect[0]);
  286. opCellNum += 3;
  287. WriteFM(opCellNum, ins->WaveSelect[1]);
  288.  
  289. /* set Feedback/Selectivity */
  290. opCellNum = (BYTE)0xC0 + (BYTE)voiceNum;
  291. WriteFM(opCellNum, ins->Feedback);
  292. } /* End of FMSetVoice */
  293.  
  294.  
  295.  
  296. /* Function: LoadSBI ********************************************************
  297. *
  298. *      Parameters:         fileName - name of .SBI file.
  299. *                          ins - variable to place data in.
  300. *
  301. *      Description:        loads a .SBI into the instrument structure.
  302. *
  303. */
  304. int LoadSBI(char fileName[], FMInstrument *ins)
  305. {
  306. int i;
  307. FILE *fp;
  308. size_t structSize = sizeof(FMInstrument);
  309.  
  310. if ((fp = fopen(fileName, "rb")) == NULL) return (0);
  311.  
  312. /* skip the header - or do we? */
  313. for (i = 0; i < 36; i++) fgetc(fp);
  314.  
  315. /* read the data */
  316. fread(ins, structSize, 1, fp);
  317.  
  318. fclose(fp);
  319. return (1);
  320. } /* End of LoadSBI */
  321.  
  322.  
  323.  
  324. /* Function: Wait **********************************************************
  325. *
  326. *      Parameters:     wait - time in microseconds
  327. *
  328. *      Description:    pauses for a specified number of microseconds.
  329. *
  330. */
  331. void Wait(clock_t wait)
  332. {
  333. clock_t goal;
  334.  
  335. if (!wait) return;
  336.  
  337. goal = wait + clock();
  338. while ((goal > clock()) && !kbhit()) ;
  339. } /* End of Wait */
  340.  
  341.  
  342.  
  343. /* test of the routines */
  344. #ifdef TEST
  345. main()
  346. {
  347. enum SCALE test[] = { D4, E4, F4, G4, A4, B4, C4 };
  348. static FMInstrument testInst =
  349. {
  350. 0x21, 0x31, 0x4F, 0x00,
  351. 0xF1, 0xF2, 0x11, 0x11,
  352. 0x00, 0x00, 0x06
  353. };
  354. int i;
  355.  
  356. printf("\nChecking for Adlib sound card...");
  357. if (!AdlibExists())
  358. {
  359. printf("not found.\n.");
  360. exit(1);
  361. }
  362. printf("found.\n");
  363. printf("Now playing tune...\n");
  364.  
  365. FMReset();
  366. FMSetVoice(0, &testInst);
  367. for (i = 0; i < 7; i++)
  368. {
  369. FMKeyOn(0, test[i], 4);
  370. Wait(25);
  371. FMKeyOff(0);
  372. Wait(1);
  373. }
  374. FMReset();
  375. }
  376. #endif
  377.